package com.example.pattern.draw

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.PointF
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import androidx.lifecycle.LifecycleOwner
import com.example.pattern.R
import com.example.pattern.draw.shape.BezelShape
import com.example.pattern.draw.shape.CircleShape
import com.example.pattern.draw.shape.CurveShape
import com.example.pattern.draw.shape.RectangleShape
import com.example.pattern.draw.shape.Shape
import com.example.pattern.draw.shape.StraightLine
import com.example.pattern.draw.shape.TriangleShape

class DrawView(context:Context,attrs:AttributeSet?):View(context, attrs) {
    var viewModel:DrawViewModel? = null
    var lifeCycleOwner:LifecycleOwner? = null
    var backgroundBitmap:Bitmap? = null
        set(value) {
            field = value
            invalidate()
        }
    private var mShapeList = arrayListOf<Shape>()
    private var mToolType = ToolType.None
    private var mLineWidth = 0
    private var mStrokeColor = 0
    private var mCurrentShape:Shape? = null
    private var mOperationType = OperationType.None
    private var mTouchX = 0f
    private var mTouchY = 0f
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),MeasureSpec.getSize(heightMeasureSpec))
    }
    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        if(viewModel != null && lifeCycleOwner != null){
            viewModel!!.mToolType.observe(lifeCycleOwner!!){
                mToolType = it
                if(mToolType == ToolType.Delete){
                    mShapeList.clear()
                    mCurrentShape = null
                    invalidate()
                }
                if(mToolType == ToolType.Back){
                    if(mShapeList.size>0){
                       mShapeList.removeLast()
                        mCurrentShape = null
                        invalidate()
                    }
                }
            }
            viewModel!!.mLineWidth.observe(lifeCycleOwner!!){
                mLineWidth = it
            }
            viewModel!!.mPaintColor.observe(lifeCycleOwner!!){
                mStrokeColor = it
            }
        }
    }

    override fun onDraw(canvas: Canvas) {
        canvas.let {
            backgroundBitmap?.let {
                canvas.drawBitmap(it,0f,0f,null)
            }
            mShapeList.forEach{shape->
                shape.draw(canvas)
            }
        }
    }

    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent?): Boolean {
        when(event?.action){
            MotionEvent.ACTION_DOWN->{
                addShape(event.x,event.y)
                mTouchX = event.x
                mTouchY = event.y
            }
            MotionEvent.ACTION_MOVE->{
                when(mOperationType){
                    OperationType.None-> {changeShape(event.x,event.y)}
                    OperationType.Translation->{
                        mCurrentShape?.move(event.x-mTouchX,event.y-mTouchY)
                        invalidate()
                        mTouchX = event.x
                        mTouchY = event.y
                    }
                    else -> {}
                }
            }
            MotionEvent.ACTION_UP->{
                mCurrentShape = null
                mOperationType = OperationType.None
            }
        }
        return true
    }
    private fun addShape(x:Float,y:Float){
        when(mToolType){
            ToolType.None->{mCurrentShape=null}
            ToolType.Line->{
                StraightLine().also{
                    initShape(it,x,y)
                }
            }
            ToolType.Rectangle->{
                RectangleShape().also {
                    initShape(it,x,y)
                }
            }
            ToolType.Circle->{
                CircleShape().also {
                    initShape(it,x,y)
                }
            }
            ToolType.Triangle->{
                TriangleShape().also{
                    initShape(it,x,y)
                }
            }
            ToolType.Curve->{
                CurveShape().also{
                    initShape(it,x,y)
                }
            }
            ToolType.Palette->{
                BezelShape().also{
                    initShape(it,x,y)
                }
            }
            ToolType.Eraser->{
                CurveShape().also {
                    initShape(it,x,y)
                    it.strokeColor = resources.getColor(R.color.background_dark,null)
                }
            }
            ToolType.Move->{
                mOperationType = OperationType.Translation
                mCurrentShape = shapeContainsPoint(x,y)
            }
            ToolType.Brush->{
                mCurrentShape = shapeContainsPoint(x,y)
                mCurrentShape?.let{
                    it.fillColor(mStrokeColor)
                    invalidate()
                    mCurrentShape = null
                }
            }
            else -> {}
        }
    }
    fun shapeContainsPoint(x:Float,y:Float):Shape?{
        for (i in mShapeList.size-1 downTo 0){
            val shape = mShapeList[i]
            if(shape.containsPoint(x,y)){
                return shape
            }
        }
        return null
    }
    private fun initShape(shape:Shape,tx:Float,ty:Float){
        shape.strokeColor = mStrokeColor
        shape.strokeWidth = mLineWidth
        shape.startPoint = PointF(tx,ty)
        mShapeList.add(shape)
        mCurrentShape = shape
    }

    private fun changeShape(x:Float,y:Float){
        mCurrentShape?.endPoint = PointF(x,y)
        invalidate()
    }
    fun isEmpty() = mShapeList.isEmpty()

}
